#include "WidgetResizer.h"
#include <QWidget>
#include <QEvent>
#include <QMouseEvent>

#define s_drag_detect_dis 2

WidgetResizer::WidgetResizer(QWidget* w)
	: QObject(w)
{
	Q_ASSERT(w != nullptr);
	m_hostWidget = w;
	if (m_hostWidget->sizePolicy() != QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed))
	{
		m_hostWidget->setMouseTracking(true);
		m_hostWidget->installEventFilter(this);
	}
}

void WidgetResizer::enable(bool v)
{
	if (v)
	{
		m_hostWidget->setMouseTracking(true);
		m_hostWidget->installEventFilter(this);
	}
	else
		m_hostWidget->removeEventFilter(this);
}

bool WidgetResizer::eventFilter(QObject* watched, QEvent* event)
{
	if (event->type() == QEvent::MouseMove)
	{
		QMouseEvent* e = static_cast<QMouseEvent*>(event);
		QPoint mousePos = e->pos();
		if (m_dragging)
		{
			mousePos = e->globalPos();
			switch (m_dragArea)
			{
			case kNone:
				break;
			case kLeft:
			{
				int delta = mousePos.x() - m_dragPos.x();
				m_hostWidget->setGeometry(m_hostWidget->geometry().adjusted(delta, 0, 0, 0));
			}
			break;
			case kTop:
			{
				int delta = mousePos.y() - m_dragPos.y();
				m_hostWidget->setGeometry(m_hostWidget->geometry().adjusted(0, delta, 0, 0));
			}
			break;
			case kRight:
			{
				int delta = mousePos.x() - m_dragPos.x();
				m_hostWidget->resize(m_hostWidget->size().grownBy(QMargins(0, 0, delta, 0)));
			}
			break;
			case kBottom:
			{
				int delta = mousePos.y() - m_dragPos.y();
				m_hostWidget->setGeometry(m_hostWidget->geometry().adjusted(0, 0, 0, delta));
			}
			break;
			case kTopLeft:
			{
				int deltaX = mousePos.x() - m_dragPos.x();
				int deltaY = mousePos.y() - m_dragPos.y();
				m_hostWidget->setGeometry(m_hostWidget->geometry().adjusted(deltaX, deltaY, 0, 0));
			}
			break;
			case kTopRight:
			{
				int deltaX = mousePos.x() - m_dragPos.x();
				int deltaY = mousePos.y() - m_dragPos.y();
				m_hostWidget->setGeometry(m_hostWidget->geometry().adjusted(0, deltaY, deltaX, 0));
			}
			break;
			case kBottomRight:
			{
				int deltaX = mousePos.x() - m_dragPos.x();
				int deltaY = mousePos.y() - m_dragPos.y();
				m_hostWidget->setGeometry(m_hostWidget->geometry().adjusted(0, 0, deltaX, deltaY));
			}
			break;
			case kBottomLeft:
			{
				int deltaX = mousePos.x() - m_dragPos.x();
				int deltaY = mousePos.y() - m_dragPos.y();
				m_hostWidget->setGeometry(m_hostWidget->geometry().adjusted(deltaX, 0, 0, deltaY));
			}
			break;
			default:
				break;
			}

			m_dragPos = mousePos;
		}
		else if(m_hostWidget->windowState() != Qt::WindowMaximized && m_hostWidget->windowState() != Qt::WindowFullScreen)
		{
			DragArea area = kNone;
			QRect r = m_hostWidget->rect();
			if ((r.topLeft() - mousePos).manhattanLength() <= 4)
				area = kTopLeft;
			else if ((r.topRight() - mousePos).manhattanLength() <= 4)
				area = kTopRight;
			else if ((r.bottomRight() - mousePos).manhattanLength() <= 4)
				area = kBottomRight;
			else if ((r.bottomLeft() - mousePos).manhattanLength() <= 4)
				area = kBottomLeft;
			else if (mousePos.x() - r.left() <= s_drag_detect_dis)
				area = kLeft;
			else if (r.right() - mousePos.x() <= s_drag_detect_dis)
				area = kRight;
			else if (mousePos.y() - r.top() <= s_drag_detect_dis)
				area = kTop;
			else if (r.bottom() - mousePos.y() <= s_drag_detect_dis)
				area = kBottom;

			m_dragArea = area;
			if (m_dragArea != kNone)
			{
				if (m_dragArea == kLeft || m_dragArea == kRight)
					m_hostWidget->setCursor(Qt::CursorShape::SizeHorCursor);
				else if (m_dragArea == kTop || m_dragArea == kBottom)
					m_hostWidget->setCursor(Qt::CursorShape::SizeVerCursor);
				else if (m_dragArea == kTopLeft || m_dragArea == kBottomRight)
					m_hostWidget->setCursor(Qt::CursorShape::SizeFDiagCursor);
				else
					m_hostWidget->setCursor(Qt::CursorShape::SizeBDiagCursor);
			}
			else
				m_hostWidget->setCursor(Qt::CursorShape::ArrowCursor);
		}
	}
	else if (event->type() == QEvent::MouseButtonPress)
	{
		QMouseEvent* e = static_cast<QMouseEvent*>(event);
		if (m_dragArea != kNone && e->button() == Qt::LeftButton)
		{
			m_dragging = true;
			m_dragPos = e->globalPos();
		}
	}
	else if (event->type() == QEvent::MouseButtonRelease)
	{
		QMouseEvent* e = static_cast<QMouseEvent*>(event);
		if (e->button() == Qt::LeftButton)
		{
			m_hostWidget->setCursor(Qt::CursorShape::ArrowCursor);
			resetDragState();
		}
	}
	else if (event->type() == QEvent::Leave)
	{
		m_hostWidget->setCursor(Qt::CursorShape::ArrowCursor);
		resetDragState();
	}

	return QObject::eventFilter(watched, event);
}

void WidgetResizer::resetDragState()
{
	m_dragging = false;
	m_dragArea = kNone;
}
